#include "stdafx.h"
#include "Graph.h"

namespace GraphTools
{
	int Vertex::GetWeightSum()
	{
		return this->sum;
	}
	list<ptr<Edge>> Vertex::GetEdges()
	{
		return this->Edges;
	}
	string Vertex::GetName()
	{
		return Name;
	}
	bool Vertex::GetFlag()
	{
		return this->flag;
	}
	void Vertex::SetFlag(bool f)
	{
		this->flag = f;
	}
	int Vertex::GetFirstWeight()
	{
		return this->first->GetWeight();
	}
	int Vertex::GetSecondWeight()
	{
		return this->second->GetWeight();
	}
	const list<weak_ptr<Vertex>> Vertex::GetNeighbours()
	{
		/*list<weak_ptr<Vertex>> neighbours = list<weak_ptr<Vertex>>();
		for (auto ite = this->Edges.begin(); ite != this->Edges.end(); ite++)
		{
			weak_ptr<Vertex> front = (*ite)->GetTerminals().front();
			weak_ptr<Vertex> back = (*ite)->GetTerminals().back();
			if ((front._Get()) == this)
			{
				neighbours.push_back(back);
			}
			else
			{
				neighbours.push_back(front);
			}
		}*/
		return this->Neighbours;
	}
	bool Vertex::operator == (const Vertex& v)
	{
		return this->Name == v.Name;
	}

	bool Vertex::operator != (const Vertex& v)
	{
		return this->Name != v.Name;
	}

	bool Vertex::AllNeighboursVisited()
	{
		for (auto ite = this->Neighbours.begin(); ite != this->Neighbours.end(); ite++)
		{
			if (ite->_Get()->flag == 0)
				return false;
		}
		return true;//for (auto ite = )
	}
	Vertex::Vertex(const string V_Name) : Name(V_Name), flag(0), sum(0), first(NULL), second(NULL), isRepeated(false) { }
	void Vertex::AddEdge(ptr<Edge> e)
	{
		this->Edges.push_back(e);
		int weight = e->GetWeight();
		if (this->first == NULL || weight > (this->first->GetWeight()))
		{
			second = first;
			first = e;
		}
		else if (this->second == NULL || weight > (this->second->GetWeight()))
		{
			second = e;
		}

		this->Neighbours.push_back(e->GetOther(*this));
		this->sum += weight;
	}

	int Vertex::GetDegree()
	{
		return this->Edges.size();
	}

	ptr<Edge> Vertex::GetThirdEdge()
	{
		if (Edges.size() < 3)
			return NULL;
		ptr<Edge> third = Edges.front();
		auto t_ite = Edges.begin();
		while ((**t_ite) == *this->first || (**t_ite) == *this->second)
			t_ite++;

		third = *t_ite;
		
		for (auto ite = Edges.begin(); ite != Edges.end(); ite++)
		{
			auto edge = (*ite);
			if (edge != this->first && edge != this->second && edge->GetWeight() > third->GetWeight())
			{
				third = edge;
			}
		}
		
		return third;
	}

	void Vertex::RemoveEdge(Edge& e)
	{
		if (this->first != NULL && !this->first._Expired() && *this->first == e)
		{
			auto third = this->GetThirdEdge();
			first = second;
			//if (this->second == NULL && this->GetDegree() > 0)
			//	cout << "Error \n" ;
			second = third;
		}
		else if (this->second != NULL && !this->second._Expired() && *this->second == e)
		{
			second = this->GetThirdEdge();
		}
		auto comparison = e.GetOther(*this)._Get();

		this->Edges.remove_if([=](ptr<Edge> an_edge) { return *an_edge == e; });
		this->Neighbours.remove_if([=](weak_ptr<Vertex> v) { return *v._Get() == *comparison; });
		this->sum -= e.GetWeight();
	}

	//void Vertex::ReduceDegreeToTwo()
	//{
	//	int old = this->GetDegree();
	//	this->Edges.clear();
	//	this->Neighbours.clear();

	//	if (this->first == NULL)
	//		cout << "errors in " << this->Name << endl;

	//	this->Edges.push_back(this->first);
	//	this->Neighbours.push_back(this->first->GetOther(*this));
	//	if (this->second != NULL)
	//	{
	//		this->Edges.push_back(this->second);
	//		this->Neighbours.push_back(this->second->GetOther(*this));
	//	}
	//	cout << "removed : " << old - 2 << endl;
	//}

	ptr<Edge> Vertex::GetSecondEdge()
	{
		//if (this->second == NULL)
		//	return NULL;
		//ptr<Edge> ret = Edges.front();
		//for (auto ite = Edges.begin(); ite != Edges.end(); ++ite)
		//{
		//	if (this->second == (*ite).get())
		//		return *ite;
		//}
		return second;
	}
	
	list<Edge*> Vertex::GetNotVisited()
	{
		auto res = list<Edge*>();
		for (auto ite = this->Edges.begin(); ite != this->Edges.end(); ++ite)
		{
			if (!(*ite)->GetFlag())
			{
				res.push_back((*ite).get());
			}
		}
		return res;
	}

	const string Vertex::ToString()
	{
		string res = Name + " ";
		for (auto ite = Edges.begin(); ite != Edges.end(); ite++)
		{
			res += (*ite)->GetWeight();
		}
		return res + "\n";
	}

	const bool Vertex::IsRepeated()
	{
		return isRepeated;
	}

	void Vertex::SetRepeated(const bool c)
	{
		isRepeated = c;
	}
}